package cn.pconline.autoclub.service;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.time.DateUtils;
import org.gelivable.dao.GeliDao;
import org.gelivable.dao.GeliOrm;
import org.gelivable.dao.SqlBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;

import cn.pconline.autoclub.entity.CheckIn;
import cn.pconline.autoclub.entity.CheckInRecord;
import cn.pconline.autoclub.entity.ClubIntegral;
import cn.pconline.autoclub.entity.ClubMember;
import cn.pconline.autoclub.util.Pager;

/**
 *
 * @author wanganning
 */
public class CheckInService {

    private static final Logger log = LoggerFactory.getLogger(CheckInService.class);
    public static int CHECKIN_DUPLICATE = 1;
    public static int CHECKIN_SUCCESS = 0;
    public static int CHECKIN_FAILED = -1;
    @Autowired
    private PlatformTransactionManager transactionManager;
    @Autowired
    private GeliDao geliDao;
    @Autowired
    private GeliOrm geliOrm;
    @Autowired
    private PetrolService petrolService;
    @Autowired
    private MemberService memberService;
    @Autowired
    private ClubService clubService;
    @Autowired
    private PagerService pagerService;
    @Autowired
    private BaseService baseService;

    public CheckIn createCheckIn(long uid, long clubId) {
        return createCheckIn(uid, clubId, 0, 0);
    }
    
    public CheckIn createCheckIn(long uid, long clubId, int total, int cont) {
        return createCheckIn(uid, clubId, total, cont, null);
    }

    /**
     * 创建签到记录
     *
     * @param uid 用户id
     * @param clubId 车友会id
     * @param total 总次数
     * @param cont 连续次数
     * @return
     */
    public CheckIn createCheckIn(long uid, long clubId, int total, int cont, Date lastCheckinAt) {
        CheckIn checkIn = new CheckIn();
        checkIn.setId(geliDao.generateId(CheckIn.class));
        checkIn.setClubId(clubId);
        checkIn.setUid(uid);
        checkIn.setTotalCheckIns(total);
        checkIn.setContinuousCheckIns(cont);
        //geliDao.create(checkIn);
        if(lastCheckinAt != null) {
            checkIn.setLastCheckInAt(lastCheckinAt);
            int lastCheckinYmd = cn.pconline.autoclub.util.DateUtils.formatData2YMD(lastCheckinAt);
            checkIn.setLastCheckinYmd(lastCheckinYmd);
        }
        boolean result = baseService.createDuplicateIgnore(checkIn);
        if(!result) {
            Map<String, Object> findParams = new HashMap<String, Object>();
            findParams.put("user_id", uid);
            findParams.put("club_id", clubId);
            try {
                checkIn = baseService.findUniqueLongKeyObject(CheckIn.class, checkIn.getClubId(), findParams);
            } catch(IncorrectResultSizeDataAccessException ex) {//历史数据问题，可能存在多条数据
               log.warn("have more than one record: {}-{}", uid, clubId);
               checkIn = getCheckInStatus(uid, clubId);
            }
        }
        return checkIn;
    }
    
    /*private CheckIn createCheckIn(long userId, long clubId) {
        
    }*/

    /**
     * 签到
     *
     * @param uid 用户id
     * @param clubId 车友会id
     * @param ip 签到ip
     * @param agent 0表示PC端 1表示wap端
     * @return 0:成功,1:一天内重复签到,-1:用户或车友会不存在
     */
    public int doCheckIn(final long uid, final long clubId, final String ip, int agent) {
        if (clubService.getValidClub(clubId) != null && memberService.isClubMember(uid, clubId)) {
          //签到操作事务处理
             /*TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
             CheckInTransactionCallback callback = new CheckInTransactionCallback(uid, clubId, ip, agent);
             int i = transactionTemplate.execute(callback);*/
             return checkIn(uid, clubId, ip, agent);
         }else{
         	return CHECKIN_FAILED;
         }
    }
    
    public int checkIn(final long uid, final long clubId, final String ip, int agent) {
        Date now = new Date();
        int todayYmd = cn.pconline.autoclub.util.DateUtils.formatData2YMD(now);
        CheckIn checkin = getCheckInStatus(uid, clubId);
        try {
            if (checkin == null) { //无签到记录，第一次签到
                checkin = createCheckIn(uid, clubId, 1, 1, now);
            } else {
                if(todayYmd == checkin.getLastCheckinYmd()) {//今天已经签到
                    return CHECKIN_DUPLICATE;
                } else if (checkin.getLastCheckInAt() != null && DateUtils.isSameDay(now, DateUtils.addDays(checkin.getLastCheckInAt(), 1))) {//昨天有签到
                    checkin.setContinuousCheckIns(checkin.getContinuousCheckIns() + 1);//连续签到加1
                } else {
                    checkin.setContinuousCheckIns(1);//签到中断，从1开始
                }
                checkin.setTotalCheckIns(checkin.getTotalCheckIns() + 1);
                checkin.setLastCheckInAt(now);
                checkin.setLastCheckinYmd(todayYmd);
                geliDao.update(checkin);
            }
            //add petrol
            ClubIntegral i = getCheckInIntegral(checkin.getContinuousCheckIns(), agent);
            //checkin log
            boolean success = createCheckinRecord(uid, clubId, ip, now, i.getPetrol());
            if(success) {
                //签到积分
                ClubMember clubMember = memberService.findMember(checkin.getUid(), checkin.getClubId());
                changeScoreForCheckIn(clubMember,i, agent);
            } else {
                return CHECKIN_DUPLICATE;
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return CHECKIN_FAILED;
        }
        return CHECKIN_SUCCESS;
    }

    private boolean createCheckinRecord(final long uid, final long clubId, final String ip, Date now, int petrol) {
        CheckInRecord checkinRecord = new CheckInRecord();
        checkinRecord.setClubId(clubId);
        checkinRecord.setUid(uid);
        checkinRecord.setIp(ip);
        checkinRecord.setCreateAt(now);
        checkinRecord.setPetrol(petrol);
        int ymd = cn.pconline.autoclub.util.DateUtils.formatData2YMD(now);
        checkinRecord.setYmd(ymd);
        return baseService.createDuplicateIgnore(checkinRecord);
    }
    
    /**
     * 删除用户签到记录
     * @param uid
     * @param clubId
     */
    public void deleteCheckIn(long uid,long clubId){
        CheckIn checkIn = getCheckInStatus(uid, clubId);
        if(checkIn==null){
            return;
        }
        geliDao.delete(checkIn,checkIn.getId());
    }
    /**
     * 昨天是否有签到,只能在今天签到之前调用判断
     *
     * @param uid 用户id
     * @param clubId 车友会id
     */
    public boolean hasCheckedInYestoday(long uid, long clubId) {
        CheckIn checkin = getCheckInStatus(uid, clubId);
        if (checkin == null) {
            return false;
        }
        return checkin.getLastCheckInAt() != null
                && DateUtils.isSameDay(checkin.getLastCheckInAt(), DateUtils.addDays(new Date(), -1));
    }

    /**
     * 查询用户在某车友会的签到信息
     *
     * @param uid 用户id
     * @param clubId 车友会id
     * @return
     */
    public CheckIn getCheckInStatus(long uid, long clubId) {
        String sql = "SELECT * FROM " + geliOrm.getTableName(CheckIn.class, clubId)
                + " WHERE user_id=? AND club_id=?";
        CheckIn checkIn = geliDao.findFirst(CheckIn.class, sql, uid, clubId);
        if(checkIn != null && checkIn.getLastCheckInAt() != null
                && checkIn.getLastCheckInAt().before(DateUtils.addDays(DateUtils.truncate(new Date(), Calendar.DATE), -1))){
            checkIn.setContinuousCheckIns(0);//只在显示上清0  数据上在每次签到的时候会计算
        }
        return checkIn;
    }

    public ClubIntegral getCheckInIntegral(int continuousCheckIns, int agent) {
        int itemId;
        switch (continuousCheckIns) {
            case 0:
                return null;
            case 1:
                itemId = agent == 0 ? PetrolService.ADD_PERSONAL_PETROL_ITEM_CHECKIN_1
                        : PetrolService.ADD_PERSONAL_PETROL_ITEM_CHECKIN_WAP_1;
                break;
            case 2:
                itemId = agent == 0 ? PetrolService.ADD_PERSONAL_PETROL_ITEM_CHECKIN_2
                        : PetrolService.ADD_PERSONAL_PETROL_ITEM_CHECKIN_WAP_2;
                break;
            case 3:
                itemId = agent == 0 ? PetrolService.ADD_PERSONAL_PETROL_ITEM_CHECKIN_3
                        : PetrolService.ADD_PERSONAL_PETROL_ITEM_CHECKIN_WAP_3;
                break;
            case 4:
                itemId = agent == 0 ? PetrolService.ADD_PERSONAL_PETROL_ITEM_CHECKIN_4
                        : PetrolService.ADD_PERSONAL_PETROL_ITEM_CHECKIN_WAP_4;
                break;
            case 5:
                itemId = agent == 0 ? PetrolService.ADD_PERSONAL_PETROL_ITEM_CHECKIN_5
                        : PetrolService.ADD_PERSONAL_PETROL_ITEM_CHECKIN_WAP_5;
                break;
            case 6:
                itemId = agent == 0 ? PetrolService.ADD_PERSONAL_PETROL_ITEM_CHECKIN_6
                        : PetrolService.ADD_PERSONAL_PETROL_ITEM_CHECKIN_WAP_6;
                break;
            case 7:
                itemId = agent == 0 ? PetrolService.ADD_PERSONAL_PETROL_ITEM_CHECKIN_7
                        : PetrolService.ADD_PERSONAL_PETROL_ITEM_CHECKIN_WAP_7;
                break;
            default:
                itemId = agent == 0 ? PetrolService.ADD_PERSONAL_PETROL_ITEM_CHECKIN_7
                        : PetrolService.ADD_PERSONAL_PETROL_ITEM_CHECKIN_WAP_7;
        }
        return petrolService.getById(itemId);
    }

    /**
     * 签到加积分
     */
    private void changeScoreForCheckIn(ClubMember clubMember,ClubIntegral i, int agent) {
//        ClubIntegral i = getCheckInIntegral(continuousCheckIns, agent);
        if (i != null) {
            petrolService.addToPersonWithinLimit(clubMember, i.getIntegralId(), i.getPetrol(), i.getName(),false,false);
        } else {
            log.error(String.format("check in fail!!!(clubIntegralId:%s)", i));
        }
    }

    class CheckInTransactionCallback implements TransactionCallback<Integer> {

        private long uid;
        private long clubId;
        private String ip;
        private int agent;

        public CheckInTransactionCallback() {
        }

        public CheckInTransactionCallback(long uid, long clubId, String ip, int agent) {
            this.uid = uid;
            this.clubId = clubId;
            this.ip = ip;
            this.agent = agent;
        }

        @Override
        public Integer doInTransaction(TransactionStatus status) {
            Date now = new Date();
            CheckIn checkin = getCheckInStatus(uid, clubId);
            if (checkin != null && checkin.getLastCheckInAt() != null
                    && DateUtils.isSameDay(checkin.getLastCheckInAt(), now)) {
                return CHECKIN_DUPLICATE;
            }
            try {
                if (checkin == null) {
                    createCheckIn(uid, clubId, 1, 1);
                } else {
                    if (hasCheckedInYestoday(uid, clubId)) {
                        checkin.setContinuousCheckIns(checkin.getContinuousCheckIns() + 1);
                    } else {
                        checkin.setContinuousCheckIns(1);
                    }
                    checkin.setTotalCheckIns(checkin.getTotalCheckIns() + 1);
                    checkin.setLastCheckInAt(now);
                    geliDao.update(checkin);
                }
                ClubIntegral i = getCheckInIntegral(checkin.getContinuousCheckIns(), agent);
                
                CheckInRecord checkinRecord = new CheckInRecord();
                checkinRecord.setClubId(clubId);
                checkinRecord.setUid(uid);
                checkinRecord.setIp(ip);
                checkinRecord.setCreateAt(now);
                checkinRecord.setPetrol(i.getPetrol());
                geliDao.create(checkinRecord);
                //签到积分
                ClubMember clubMember = memberService.findMember(checkin.getUid(), checkin.getClubId());
                changeScoreForCheckIn(clubMember,i, agent);
            } catch (Exception e) {
            	log.error(e.getMessage());
                status.setRollbackOnly();
                return CHECKIN_FAILED;
            }
            return CHECKIN_SUCCESS;
        }
    }

    /**
     * 分页获取今天的签到人数
     * @param clubId
     * @param pageNo
     * @param pageSize
     * @return
     */
	public Pager<CheckIn> pagerForClubId(long clubId, int pageNo, int pageSize) {
		
		SqlBuilder sql = new SqlBuilder();
		sql.appendSql(" select id from ").appendSql(geliOrm.getTableName(CheckIn.class,clubId)).appendSql(" where 1=1 ");
		if(clubId>0){
			sql.appendSql(" and club_id = ").appendValue(clubId);
		}
		sql.appendSql(" and TO_DAYS(`last_checkin_at`) = TO_DAYS(NOW()) ");
		sql.appendSql(" order by last_checkin_at desc");
		
		return pagerService.pager(CheckIn.class,clubId, sql, pageNo, pageSize);
	}
	
	 /**
	  * 判断今天是否已签到
	  * @param userId
	  * @param clubId
	  * @return
	  */
	public boolean isCheckInToday(long userId, long clubId) {

		CheckIn checkIn = getCheckInStatus(userId, clubId);
		if (checkIn == null) {
			checkIn = createCheckIn(userId, clubId);
		}
		int todayYmd = cn.pconline.autoclub.util.DateUtils.formatData2YMD(new Date());
		return todayYmd == checkIn.getLastCheckinYmd();
	}
}
